/*
 * @Author: FengXiao
 * @Date: 2021-05-24 09:30:39
 * @LastEditors: FengXiao
 * @LastEditTime: 2021-06-03 15:45:02
 */
import CryptoJS from 'crypto-js';
import { JSEncrypt } from './jsencrypt';
import { getRSAPublicKey, getAESKey } from '@/api/crypto';
import { uuidv4 } from './index';

function getKey(key) {
    key = CryptoJS.enc.Utf8.parse(key.toString());
    key = CryptoJS.enc.Base64.stringify(key);
    key = CryptoJS.enc.Base64.parse(key);
    return key;
}

export function encrypt(text, key) {
    key = getKey(key);
    return CryptoJS.AES.encrypt(text, key, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7,
    }).toString();
}

export function decrypt(text, key) {
    key = getKey(key);
    let decrypted = CryptoJS.AES.decrypt(text, key, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7,
    });
    return decrypted.toString(CryptoJS.enc.Utf8);
}

// rsa 加密
export function rsaKEY(data, pubkey) {
    let encryptor = new JSEncrypt();
    encryptor.setPublicKey(pubkey);
    return encryptor.encryptLong(data);
}

// rsa 解密
export function decryptKey(data, pubkey) {
    let decryptor = new JSEncrypt();
    decryptor.setPrivateKey(pubkey);
    return decryptor.decrypt(data);
}

const RSA2text = (buffer, isPrivate = 0) => {
    let binary = '';
    const bytes = new Uint8Array(buffer);
    const len = bytes.byteLength;
    for (let i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    const base64 = window.btoa(binary);
    let text = '';
    // "-----BEGIN " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----\n";
    text += base64.replace(/[^\x00-\xff]/g, '$&\x01').replace(/.{64}\x01?/g, '$&\n');
    // text +=
    //   "\n-----END " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----";
    return text;
};

//获取密钥对
export const getRsaKeys = () => {
    return new Promise(async (resolve, reject) => {
        const data = {
            name: 'RSA-OAEP',
            modulusLength: 2048,
            publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            hash: { name: 'SHA-512' },
        };
        try {
            const key = await window.crypto.subtle.generateKey(data, true, ['encrypt', 'decrypt']);
            const keydata1 = await window.crypto.subtle.exportKey('pkcs8', key.privateKey);
            const keydata2 = await window.crypto.subtle.exportKey('spki', key.publicKey);
            const privateKey = RSA2text(keydata1, 1);
            const publicKey = RSA2text(keydata2);
            resolve({ privateKey, publicKey });
        } catch (err) {
            console.log(err);
            reject(err);
        }
    });
};

// 生成公私钥
export async function generateKey() {
    return getRsaKeys();
}

// 1.前端请求后端，后端使用RSA工具类生成一对公钥私钥 pubKey1,priKey1 ,将pubKey1返回给前端
// 2.前端自己使用RSA算法生成一对公钥私钥pubKey2,priKey2
// 3.前端使用pubKey1将pubKey2加密传给后端，后端使用priKey1解密得到pubKey2.
// 4.后端使用pubKey2将AES的密钥加密并返回。
// 5.前端使用priKey2解密，得到AES加密的密钥。
// 6.使用密钥解密后端响应，得到最终结果
export async function getAESInfo(retryTime = 0) {
    if (retryTime > 5) {
        throw new Error('获取密钥失败，请稍后重试');
    }
    const clientId = uuidv4();
    const pubKey = await getPubKey(clientId); // 1
    const currentKey = await generateKey(); // 2
    const data = rsaKEY(currentKey.publicKey, pubKey);
    let AESKey;
    try {
        AESKey = await getAESPriKey({ clientId, data }, currentKey); // 3-4
    } catch (e) {
        if (e.code === '019') {
            return await getAESInfo(retryTime + 1);
        } else {
            throw e;
        }
    }
    return { clientId, currentKey, AESKey };
}

const getPubKey = async (clientId) => {
    try {
        return await getRSAPublicKey(clientId);
    } catch (error) {
        console.log(error, '获取公钥失败~');
    }
};

const getAESPriKey = async (data, currentKey) => {
    return decryptKey(await getAESKey(data), currentKey.privateKey);
};
